#pragma once
#include <string>
#include <iostream>
#include <fstream>
#include <filesystem> //c++17, 需要高标准编译器和-std=c++17
#include <mutex>
#include <unistd.h>
#include <ctime>
#include <stdio.h>
#include <sstream> //stringstream
#include <memory>


namespace wzx
{
    //策略模式
    class log_strategy
    {
    public:
        virtual bool refresh(const std::string& message) = 0; //不同策略即不同刷新方式: 显示器or文件
    };

    //控制台日志策略, 即向显示器刷新日志
    class console_log_strategy : public log_strategy
    {
    public:
        virtual bool refresh(const std::string& message) override   
        {
            std::lock_guard<std::mutex> LG(_mutex);//显示器是临界资源, 加锁保护线程安全
            std::cout << message << std::endl;
            return true;
        }
        
    private:
        std::mutex _mutex;
    };

    //文件日志策略
    #define DEFAULT_LOG_PATH "./log/"
    #define DEFAULT_LOG_NAME "mylog.txt"

    class file_log_strategy : public log_strategy
    {
    public: 
        file_log_strategy(const std::string& log_path = DEFAULT_LOG_PATH, const std::string& log_name = DEFAULT_LOG_NAME)
            :_log_path(log_path)
            ,_log_name(log_name)
        {
            std::lock_guard<std::mutex> LG(_mutex);//同理

            if(std::filesystem::exists(_log_path))//只需要判断路径是否存在即可, 因为在写文件时不存在的文件会被自动创建
                return;            

            try
            {
                std::filesystem::create_directories(_log_path);
            }
            catch(const std::filesystem::filesystem_error& e)
            {
                std::cerr << e.what() << std::endl;
            }
        }


        virtual bool refresh(const std::string& message) override   
        {
            std::lock_guard<std::mutex> LG(_mutex);//文件是临界资源
            std::string log = _log_path + (_log_path.back() == '/' ? "" : "/") + _log_name;
            std::ofstream out(log.c_str(), std::ios::app);//追加方式

            if(!out.is_open())//打开失败了
                return false;

            out << message << std::endl;
            out.close();
            return true;
        }
    
    private:
        std::string _log_path;
        std::string _log_name;
        std::mutex _mutex;
    };

}